package io.itit.ecp.admin.provide.renderer;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.constants.EcpAdminConstants;
import io.itit.ecp.admin.provide.action.req.CarbonEmissionPlanQueryReq;
import io.itit.ecp.admin.provide.action.req.CarbonEmissionPlanReq;
import io.itit.ecp.admin.provide.action.resp.SceneEdificeResp;
import io.itit.ecp.admin.provide.action.resp.SceneFloorResp;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.entity.extend.CarbonEmissionPlanExtEntity;
import io.itit.ecp.admin.server.service.*;
import io.itit.grass.common.exception.GrassException;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.estelle.starter.parse.AbstractParseRenderer;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * @Author：Roy
 * @Description：碳排放规划配置导入解析器
 * @Date：Create by 2024-01-11 16:45:38
 */
@Scope("prototype")
@Component(CarbonEmissionPlanRenderer.ENTITY_NAME)
public class CarbonEmissionPlanRenderer extends AbstractParseRenderer<CarbonEmissionPlanExtEntity> {

    public static ThreadLocal<CarbonEmissionPlanQueryReq> threadLocal = new ThreadLocal<>();

    public static final String ENTITY_NAME = "carbonEmissionPlanRenderer";

    private Map<String, String> sceneProjectMap;

    private Map<String, String> sceneEdificeMap;

    private Map<String, String> sceneFloorMap;

    @Resource
    private ISceneProjectService sceneProjectService;
    @Resource
    private ICarbonEmissionPlanService carbonEmissionPlanService;
    @Resource
    private ICarbonEmissionPlanDetailService carbonEmissionPlanDetailService;
    @Resource
    private ICarbonEmissionPlanDataService carbonEmissionPlanDataService;
    @Resource
    private ISceneFloorService sceneFloorService;
    @Resource
    private ICarbonEmissionUnplanService carbonEmissionUnplanService;

    @Override
    public String entityName() {
        return ENTITY_NAME;
    }

    @Override
    public Class<CarbonEmissionPlanExtEntity> getClazz() {
        return CarbonEmissionPlanExtEntity.class;
    }

    @Override
    public void processBefore() {
        sceneProjectMap = sceneProjectService.lambdaQuery()
                .list()
                .stream()
                .collect(Collectors.toMap(SceneProjectEntity::getProjectName, SceneProjectEntity::getId));

        sceneEdificeMap = Joins.of(SceneEdificeEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, SceneEdificeEntity::getSceneProjectId)
                .select(SceneProjectEntity::getProjectName)
                .end()
                .joinList(SceneEdificeResp.class)
                .stream()
                .collect(Collectors.toMap(x -> key(x.getProjectName(), x.getEdificeName()), SceneEdificeResp::getId));

        sceneFloorMap = Joins.of(SceneFloorEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, SceneFloorEntity::getSceneProjectId)
                .select(SceneProjectEntity::getProjectName)
                .end()
                .leftJoin(SceneEdificeEntity.class, SceneEdificeEntity::getId, SceneFloorEntity::getSceneEdificeId)
                .select(SceneEdificeEntity::getEdificeName)
                .end()
                .joinList(SceneFloorResp.class)
                .stream()
                .collect(Collectors.toMap(x -> key(x.getProjectName(), x.getEdificeName(), x.getFloorName()), SceneFloorResp::getId));
    }

    @Override
    public void verify(CarbonEmissionPlanExtEntity entity) {
        CarbonEmissionPlanQueryReq req = CarbonEmissionPlanRenderer.threadLocal.get();
        addErrorMsg(req.getEffectiveTimeStart() == null, "生效开始时间不能为空！");
        addErrorMsg(req.getEffectiveTimeEnd() == null, "生效结束时间不能为空！");

        addErrorMsg(StringUtils.isEmpty(entity.getProjectName()) || !sceneProjectMap.containsKey(entity.getProjectName()), "所属项目【" + entity.getProjectName() + "】不存在！");
        addErrorMsg(StringUtils.isEmpty(entity.getEdificeName()) || !sceneEdificeMap.containsKey(key(entity.getProjectName(), entity.getEdificeName())), "所属楼栋【" + entity.getProjectName() + "/" + entity.getEdificeName() + "】不存在！");
        addErrorMsg(StringUtils.isEmpty(entity.getFloorName()) || !sceneFloorMap.containsKey(key(entity.getProjectName(), entity.getEdificeName(), entity.getFloorName())), "所属楼层【" + entity.getProjectName() + "/" + entity.getEdificeName() + "/" + entity.getFloorName() + "】不存在！");

        entity.setSceneProjectId(sceneProjectMap.get(entity.getProjectName()));
        entity.setSceneEdificeId(sceneEdificeMap.get(key(entity.getProjectName(), entity.getEdificeName())));
        entity.setSceneFloorId(sceneFloorMap.get(key(key(entity.getProjectName(), entity.getEdificeName(), entity.getFloorName()))));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int processAfter(List<CarbonEmissionPlanExtEntity> resultList) {
        CarbonEmissionPlanQueryReq req = CarbonEmissionPlanRenderer.threadLocal.get();
        if (CollectionUtils.isEmpty(resultList)) {
            return 0;
        }
        Map<String, List<CarbonEmissionPlanExtEntity>> edificeMap = resultList.stream().collect(Collectors.groupingBy(x -> key(x.getSceneProjectId(), x.getSceneEdificeId())));
        List<CarbonEmissionPlanEntity> planEntityList = new ArrayList<>();
        List<CarbonEmissionPlanDetailEntity> planDetailEntityList = new ArrayList<>();
        for (Map.Entry<String, List<CarbonEmissionPlanExtEntity>> entry : edificeMap.entrySet()) {
            String[] keys = entry.getKey().split(EcpAdminConstants.COLON);
            CarbonEmissionPlanEntity planEntity = new CarbonEmissionPlanExtEntity();
            planEntity.setSceneProjectId(keys[0]);
            planEntity.setSceneEdificeId(keys[1]);
            planEntity.setEffectiveTimeStart(req.getEffectiveTimeStart());
            planEntity.setEffectiveTimeEnd(req.getEffectiveTimeEnd());
            Long aLong = checkDate(ConvertUtils.convertIgnoreId(planEntity, CarbonEmissionPlanReq.class));
            if (aLong > 0) {
                GrassException.throwEx("当前已设置生效时间范围：" + DateUtil.format(req.getEffectiveTimeStart(), DatePattern.NORM_DATE_PATTERN) + "/" + DateUtil.format(req.getEffectiveTimeEnd(), DatePattern.NORM_DATE_PATTERN) + ", 不可重复设置已有时间范围 !");
            }
            Long count = sceneFloorService.lambdaQuery().eq(SceneFloorEntity::getSceneEdificeId, keys[1]).count();
            if (count != entry.getValue().size()) {
                GrassException.throwEx("当前项目【" + entry.getValue().get(0).getProjectName() + "】楼栋【" + entry.getValue().get(0).getEdificeName() + "】楼层共【" + count + "】层 , 导入楼层数量【" + entry.getValue().size() + "】, 每层【电、水、冷】规划碳排必须配置，请配置完成！");
            }
            carbonEmissionUnplanService.buildData(planEntity);
            planEntityList.add(planEntity);
            CarbonEmissionPlanExtEntity extEntity = ConvertUtils.convert(planEntity, CarbonEmissionPlanExtEntity.class);
            List<CarbonEmissionPlanDetailEntity> detailList = new ArrayList<>();
            for (CarbonEmissionPlanExtEntity planDetail : entry.getValue()) {
                CarbonEmissionPlanDetailEntity planDetailEntity = new CarbonEmissionPlanDetailEntity();
                planDetailEntity.setCarbonEmissionPlanId(planEntity.getId());
                planDetailEntity.setSceneProjectId(keys[0]);
                planDetailEntity.setSceneEdificeId(keys[1]);
                planDetailEntity.setSceneFloorId(planDetail.getSceneFloorId());
                planDetailEntity.setElectric(planDetail.getElectric());
                planDetailEntity.setWater(planDetail.getWater());
                planDetailEntity.setCold(planDetail.getCold());
                planDetailEntityList.add(planDetailEntity);
                detailList.add(planDetailEntity);
            }
            extEntity.setPlanDetailList(detailList);
            carbonEmissionPlanDataService.saveData(extEntity);

        }

        carbonEmissionPlanService.saveBatch(planEntityList);
        carbonEmissionPlanDetailService.saveBatch(planDetailEntityList);

        threadLocal.remove();
        return edificeMap.size();
    }

    private String key(String... projectName) {
        return String.join(":", projectName);
    }

    private Long checkDate(CarbonEmissionPlanReq req) {
        return carbonEmissionPlanService.lambdaQuery()
                .eq(CarbonEmissionPlanEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(CarbonEmissionPlanEntity::getSceneEdificeId, req.getSceneEdificeId())
                .ge(CarbonEmissionPlanEntity::getEffectiveTimeEnd, req.getEffectiveTimeStart())
                .le(CarbonEmissionPlanEntity::getEffectiveTimeStart, req.getEffectiveTimeEnd()).count();
    }
}
